--[[
	
	TODO: дофига всего

]]

instead_version "1.3.4"

require "timer"
require "kbd"

-- global game variables

global {
	ts = 32;						-- tile size (in pixels)
	
	xoff = 8;						-- constant x offset
	yoff = 8;						-- constant y offset
};

-- global view variables

global {

	viewx = 1;						-- current view x
	viewy = 1;						-- current view y
	
	viewwidth = (xoff*2+1);			-- view width
	viewheight = (yoff*2+1);		-- view height

}

-- Other global vars

heartbeat = obj {
	
	nam = "heartbeat",
	life = function()
		
	end;

}


		

game.timer = function()
	if not step(direction) then
		return nil
	end;
	return true;
end;

-- you, player

pl = player {
	
	nam = "You",
	var {
		x = 13;
		y = 13;
	},
	pic = "man.png",
	
}

-- draw_tile -- adds a tile to a buf at x,y

function draw_tile(buf, img, x, y)
	buf = buf..img.."@"..x..","..y..";";
	return buf;
end;


-- stats object (VERY handy!)

stats = stat {
	nam = function()
		p("view x/y: "..viewx.."/"..viewy.."|"..
		"view w/h: "..viewwidth.."/"..viewheight.."|"
		.."player x/y: "..me().x.."/"..me().y.."|"..
		"Game time: "..time().."||".."Сообщения:");
	end;
}

messages = stat {

	nam = "Сообщения",
	disp = '',

}


-- input handling

input.key = function(s,pr,key)		
	if key == "right" or key == "left" or key == "up" or key == "down" then 
		if pr then
			if timer:get() == 0 then
				direction = key;
				timer:set(85);
			else
				direction = key;
			end;
		else
			timer:stop();
		end;		
	end;

end;

-- collision checking

function coll(x, y)
	if y < 1 or x < 1 or y > #here().map or x > #here().map[y] then
		return true;
	else
		if type(here().map[y][x]) == "table" then
			local object;
			if objs():srch(here().map[y][x][2]) then
				object = objs():srch(here().map[y][x][2]);
			elseif isObject(here().map[y][x][2]) then
				object = here().map[y][x][2];
			else
				object = false;
			end;
			if object then
				if object.action then
					if type(object.action) == 'function' then
						call(object, "action");
					else
						messages.disp = object.action;
					end;
				end;
				if object.solid == true or links[here().map[y][x][1]].solid == true then
					return true;
				else
					return false;
				end;
			else
				if links[here().map[y][x][1]].solid then
					return true;
				else
					return false;
				end;
			end;
		else
			if links[here().map[y][x]].solid then
				return true;
			else
				return false;
			end;
		end;
	end;
end;

-- moving around

function step(direction)
	messages.disp = '';
	local x = me().x;
	local y = me().y;
	if direction == "left" then
		if coll(x-1, y) then
			return false;
		else
			me().x = x-1;
		end;
	elseif direction == "right" then  
		if coll(x+1, y) then
			return false;
		else
			me().x = x+1;
		end;
	elseif direction == "up" then
		if coll(x, y-1) then
			return false;
		else
			me().y = y-1;
		end;
	elseif direction == "down" then
		if coll(x, y+1) then
			return false;
		else
			me().y = y+1;
		end;
	else 
		return false;
	end;
	return true;
end;

-- This functions obviously draws game

-- draw game on a canvas (very slow... maybe fast in future releases)
function draw_game_sprites()
	local buf = '';
	local vw = viewwidth - 1;
	local vh = viewheight - 1;
	
	
	-- prepare canvas
	buf = buf.."box:"..viewwidth*ts.."x"..viewheight*ts..",black,255;";
		
	-- refresh view coordinates	
	viewx = me().x - xoff;
	viewy = me().y - yoff;
	
	-- map bounds check (x)
	if viewx < 1 then
		viewx = 1;
	elseif viewx+vw > #here().map[1] then
		viewx = #here().map[1] - vw;
	end;
	
	-- map bounds check (y)
	if viewy < 1 then
		viewy = 1;
	elseif viewy+vh > #here().map then
		viewy = #here().map - vh;
	end;
	
	for y=viewy, viewy+vh, 1 do
		for x=viewx, viewx+vw, 1 do
			buf = draw_tile(buf, links[here().map[y][x]].pic, (x-viewx)*ts, (y-viewy)*ts);
		end;
	end;
	
	buf = draw_tile(buf, me().pic, (me().x-viewx)*ts, (me().y-viewy)*ts);
	
	return img(buf);
end;

-- draw game with lots of img() (much faster)
function draw_game()
	local buf = '';
	local vw = viewwidth - 1;
	local vh = viewheight - 1;
	
	-- refresh view coordinates	
	viewx = me().x - xoff;
	viewy = me().y - yoff;
	
	-- map bounds check (x)
	if viewx < 1 then
		viewx = 1;
	elseif viewx+vw > #here().map[1] then
		viewx = #here().map[1] - vw;
	end;
	
	-- map bounds check (y)
	if viewy < 1 then
		viewy = 1;
	elseif viewy+vh > #here().map then
		viewy = #here().map - vh;
	end;
	
	for y=viewy, viewy+vh, 1 do
		for x=viewx, viewx+vw, 1 do
			if type(here().map[y][x]) == "table" then
				local object;
				if objs():srch(here().map[y][x][2]) then
					object = objs():srch(here().map[y][x][2]);
				elseif isObject(here().map[y][x][2]) then
					object = here().map[y][x][2];
				else
					object = false;
				end;
				if object then
					if x == me().x and y == me().y then
						buf = buf..img(links[here().map[y][x][1]].pic..";"
						..me().pic.."@0,0;"..object.pic.."@0,0;");
					else
						buf = buf..img(links[here().map[y][x][1]].pic..";"
						..object.pic.."@0,0;");
					end;
				else
					buf = buf..img(links[here().map[y][x][1]].pic);
				end;
			else
				if x == me().x and y == me().y then
					buf = buf..img(links[here().map[y][x]].pic..";"..me().pic.."@0,0;");
				else
					buf = buf..img(links[here().map[y][x]].pic);
				end;
			end;
		end;
		buf = buf.."^";
	end;
	
	return buf;
end;


-- groom instead of room (graphical)

groom = stead.inherit(room, function(v)
	v.look = stead.hook(v.look, function(f, s, ...)
		return draw_game();
	end)
	return v
end)


-- simple tile (with solidness)

tile = function(n, p, s)
	local t = {};
	if s == nil then
		s = false;
	end;
	t = {
		nam = n,
		pic = p,
		solid = s,
	};
	return t;
end;


-- links: connections between maps and tiles/objects

global {

	
	links = {
		
		['0'] 		= tile("Гора", "wall.png", true),
		['1'] 		= tile("Дорога", "road.png");
		['2'] 		= tile("Трава", "grass.png");
		['3']		= tile("Кирпич", "kirpich.png", true);
		['4']		= tile("Пол", "floor.png");
	} 

};

function door_construct() 
	return obj {
		nam = 'door',
		var {
			opened = false,
			solid = true,
			pic = 'kirpichdoor.png',
		},
		action = function(s)
			if s.solid then
				if s.opened then
					
				else
					s.pic = 'kirpichdooropen.png';
					messages.disp = 'Вы открыли дверь.';
					s.opened = true;
					s.solid = false;
				end;
			end
		end;
	};
end;

function actionobj(p, ac)
	local t = {};
	t.nam = "action";
	t.pic = p..".png";
	t.action = ac;
	return obj(t);
end;

function a(p, ac) 
	local t = 'actionobj([['..p..']], [['..ac..']])';
	return new(t);
end;

function door()
	return new('door_construct()');
end;

	
main = groom {
	nam = 'Test Room';
	disp = '',
	-- testing map
	var {
		map = {
			{'2','3', '3', {'3', a('tablichka', 'На табличке надпись:|"Добро пожаловать!"')}, '3', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '4', '4', '4', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '4', '4', '4', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2',{'3', a('picture', 'На картине изображен меч.')}, '4', '4', '4', {'4', door()} ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '4', '4', '4', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '4', '4', '4', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '4', '4', '4', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','3', '3', {'4', door()}, '3', '3' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
			{'2','2', '2', '1', '2', '2' ,'2', '2', '2', '2', '2', '2', '2', '2' ,'2', '2', '2'},
		},
	};
	
};

function init()
	put('stats', me());
	put('messages', me());
	lifeon('heartbeat');
end;
